home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 07 - 1991 / Goodies Disk / Pop Up Menu CDEF 1.4 Final / Pop Up Menu CDEF 1.4.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-06  |  37.6 KB  |  964 lines  |  [TEXT/KAHL]

  1. /* Pop Up Menu CDEF.c                                                    */
  2. /*                                                                        */
  3. /*    By:                                                                    */
  4. /*        Chris Faigle                                                    */
  5. /*                                                                        */
  6. /*    With ideas, code, bug fixes, testing, time, and effort by:            */
  7. /*        Rick Aurbach                                                    */
  8. /*        Pete Deignan                                                    */
  9. /*        Joe Schwartz                                                    */
  10. /*        Mike Puckett                                                    */
  11. /*        Steve Hutcherson                                                */
  12. /*        Doug McKenna                                                    */
  13. /*        Jerry Shields                                                    */
  14. /*        Ton Mommers                                                        */
  15. /*        Christoph Sold                                                    */
  16. /*        Robert Mah                                                        */
  17. /*        Tom Becker                                                        */
  18. /*        and others..                                                    */
  19. /*                                                                        */
  20. /*                                                                        */
  21. /*    Version 1.4 Final                                                    */
  22. /*    September, 1990                                                        */
  23. /*                                                                        */
  24. /*                                                                        */
  25. /*    This software is now in the Public Domain, providing the following:    */
  26. /*        No fee other than normal copying or bulletin-board time fees    */
  27. /*        may be charged for this software.  The CDEF may be included in    */
  28. /*        commercial software without fees or notices.  Portions of the    */
  29. /*        CDEF are copyright Symantec Corp.                                */
  30. /*                                                                        */
  31. /*    If you make enhancements to this software, PLEASE send me a copy!    */
  32. /*                                                                        */
  33. /*    Address any correspondence/bug reports/suggestions to:                */
  34. /*    Chris Faigle                                                        */
  35. /*    c/o Performance Software                                            */
  36. /*    575 SouthLake Blvd                                                    */
  37. /*    Richmond, VA  23236                                                    */
  38. /*    AppleLink:  CHRIS.FAIGLE                                            */
  39. /*                                                                        */
  40. /*    Please Read ‘Pop Up Menu CDEF Instructions’ for more info            */
  41. /*                                                                        */
  42.  
  43.  
  44. #include "ControlMgr.h"
  45. #include "SetUpA4.h"
  46.  
  47.  
  48. #define    LEFT_SPACE                    15        /* Changed from 13 1.4b3    */
  49. #define    IN_MENU                        1
  50. #define    INACTIVE                    255
  51. #define    LOW_31_BITS_MASK            0x7FFFFFFF
  52. #define    CODE_MASK                    0x000F
  53. #define    HI_BYTE                        0xFF00
  54. #define    LO_BYTE                        0x00FF
  55. #define    TITLED_MASK                    0x0001
  56. #define    NEW_STYLE_MASK                0x0002
  57. #define    CHECK_MASK                    0x0004
  58. #define    EXTRA_SPACE_FOR_NEW_STYLE    13
  59. #define    SICN_SPACE                    20
  60. #define    RICN_SPACE                    20
  61. #define    ICON_SPACE                    36
  62. #define    RICN_MENU                    29
  63. #define    SICN_MENU                    30
  64. #define    NORMAL_MENU_SIZE            16
  65. #define    RICN_MENU_SIZE                20
  66. #define    SICN_MENU_SIZE                20
  67. #define    ICON_MENU_SIZE                36
  68.  
  69.  
  70. typedef    short        SICN[16];        /* This info is in Tech Note #252:        */
  71. typedef    SICN        *SICNList;        /* “Plotting Small Icons”                */
  72. typedef    SICNList    *SICNHand;
  73.  
  74.  
  75. typedef struct
  76. {
  77.     short        type;
  78.     short        we_loaded_the_menu;
  79.     MenuHandle    the_menu;
  80. } pop_up_data_struct,**pop_up_data_handle;
  81.  
  82.  
  83. typedef struct
  84. {
  85.     short        save_size;
  86.     short        save_font;
  87.     Style        save_face;
  88.     PenState    save_pen;
  89. } pen_font_struct,**pen_font_handle;
  90.  
  91.  
  92. #ifndef    calcCntlRgn
  93. #define    calcCntlRgn                    10
  94. #endif
  95.  
  96. #ifndef    calcThumbRgn
  97. #define    calcThumbRgn                11
  98. #endif
  99.  
  100. #ifndef NULL
  101. #define    NULL                        0l
  102. #endif
  103.  
  104. /* Declare function return values:            */
  105. long        draw_control();
  106. long        test_control();
  107. long        calculate_control_region();
  108. long        initialize_control();
  109. long        dispose_control();
  110. long        position_control();
  111. long        thumb_control();
  112. long        drag_control();
  113. long        auto_track_control();
  114. MenuHandle    get_pop_menu();
  115. short        calculate_retangles();
  116. short        draw_pop_up_symbol();
  117. short        save_pen_font();
  118. short        set_pen_font();
  119. short        gray_out_rectangle();
  120. short        plot_sicn();
  121. void        shrink_string();
  122. pascal void new_calc_menu_size();
  123. short        trap_calc_menu_size();
  124. void        convert_rectangle();
  125. short        check_color();
  126.  
  127. /* Declare our trap address global variables        */
  128. void         (*real_calc_menu_size)();
  129. short        pop_up_menu_width;
  130.  
  131.  
  132. pascal long main(short code,ControlHandle the_control,short message,long parameter)
  133. {
  134.     long            return_value;
  135.     short            control_type;
  136.     pen_font_struct    save_struct;
  137.     short            the_id;
  138.     long            the_type;
  139.     Str255            the_name;
  140.  
  141.     RememberA0();
  142.     SetUpA4();
  143.     HLock(the_control);                                    /* Lock the control handle                */
  144.     save_pen_font(the_control,&save_struct);            /* Save off the pen, font, style        */
  145.     GetResInfo(the_control,&the_id,&the_type,&the_name);
  146.     if(ResError()!=resNotFound)
  147.     {
  148.         SysBeep(1);
  149.     }
  150.     control_type=BitAnd(code,CODE_MASK);                /* Find out type 0=No Title 1=Title        */
  151.     switch(message)                                        /* Which Message were we sent??            */
  152.     {
  153.         case drawCntl:
  154.                     adjust_max_and_min(the_control);    /* First, adjust the Max and Min Values    */
  155.                     return_value=draw_control(control_type,the_control,parameter);
  156.                     break;
  157.         case testCntl:
  158.                     return_value=test_control(control_type,the_control,parameter);
  159.                     break;
  160.         case calcCRgns:
  161.                     parameter&=LOW_31_BITS_MASK;        /* Strip off High Bit                    */
  162.         case calcCntlRgn:
  163.         case calcThumbRgn:
  164.                     return_value=calculate_control_region(control_type,the_control,parameter);
  165.                     break;
  166.         case initCntl:
  167.                     return_value=initialize_control(control_type,the_control,parameter);
  168.                     break;
  169.         case dispCntl:
  170.                     return_value=dispose_control(control_type,the_control,parameter);
  171.                     break;
  172.         case posCntl:
  173.                     return_value=position_control(control_type,the_control,parameter);
  174.                     break;
  175.         case thumbCntl:
  176.                     return_value=thumb_control(control_type,the_control,parameter);
  177.                     break;
  178.         case dragCntl:
  179.                     return_value=drag_control(control_type,the_control,parameter);
  180.                     break;
  181.         case autoTrack:
  182.                     return_value=auto_track_control(control_type,the_control,parameter);
  183.                     break;
  184.     }
  185.     set_pen_font(&save_struct);                            /* Restore the pen, font, style            */
  186.     HUnlock(the_control);                                /* Unlock the control handle            */
  187.     RestoreA4();
  188.     return(return_value);
  189. }
  190.  
  191.  
  192. long draw_control(short control_type,ControlHandle the_control,long parameter)
  193. {
  194.     Str255            current_selection_text;            /* Text of the current menu item                                */
  195.     Rect            control_rectangle;                /* Rectangle of the actual menu item                            */
  196.     Rect            title_rect;                        /* Rectangle containing the title if any                        */
  197.     FontInfo        font_info;                        /* Font info of the current font                                */
  198.     Point            text_point;                        /* The point where we draw the text                                */
  199.     short            titled;                            /* Does this control have a title?                                */
  200.     short            new_style;                        /* Is is a new style pop up?                                    */
  201.     short            ball_check_char;                /* Should we use the '•' as a check character                    */
  202.     short            use_window_font;                /* Should we use the window's font for the title?                */
  203.     short            active;                            /* Is this control active?                                        */
  204.     short            visible;                        /* Is this control visible?                                        */
  205.     MenuHandle        the_menu;                        /* The control's menu                                            */
  206.     short            command_char;                    /* This is used to determine if there is a ricn, sicn, etc.        */
  207.     short            which_sicn;                        /* The sicn if it exists                                        */
  208.     short            which_icon;                        /* The icon if it exists                                        */
  209.     Rect            icon_rect;                        /* The rectangle to plot the icon in                            */
  210.     Handle            icon_handle;                    /* The handle to the Icon                                        */
  211.     short            space_on_left;                    /* The space to the left of the menu item                        */
  212.     short            item_style;                        /* Text Face of the Item                                        */
  213.     short            color_qd_implemented;            /* Is Color QuickDraw Implemented?                                */
  214.     MCEntryPtr        item_color_ptr;                    /* The colors of the menu item                                    */
  215.     RGBColor        background_color;                /* Current background color                                        */
  216.     RGBColor        foreground_color;                /* Current foreground color                                        */
  217.     short            space_for_string;                /* Space available for item string                                */
  218.     short            have_item_color=FALSE;            /* Do we need to set color values for this item                    */
  219.     RGBColor        item_foreground_color;            /* Items foreground color                                        */
  220.     RGBColor        item_background_color;            /* Item's background color                                        */
  221.     short            has_enough_pixel_depth;            /* Used in determining if we have enough depth to support color    */
  222.     Point            conversion_point;                /* Used in converting Local to Global to Local                    */
  223.     Rect            intersection_rect;                /* Dummy rectangle used in SecRect                                */
  224.     GDHandle        check_device;                    /* Graphics device we are checking for pixel depth                */
  225.  
  226.     titled=control_type&TITLED_MASK;                /* Is there a title?                                            */
  227.     new_style=control_type&NEW_STYLE_MASK;            /* Is it the New Style?                                            */
  228.     color_qd_implemented=check_color();
  229.     space_on_left=LEFT_SPACE;                        /* Use the normal amount of space on the left    (1.4b2)            */
  230.     ball_check_char=control_type&CHECK_MASK;        /* Use the '•' check char?                                        */
  231.     use_window_font=control_type&useWFont;            /* Use the Window's Font?                                        */
  232.     if((**the_control).contrlHilite==INACTIVE)        /* Is the control inactive??                                    */
  233.     {
  234.         active=FALSE;                                /* Yes - set active flag to FALSE                                */
  235.     }
  236.     else                                            /* No - set active flag to TRUE                                    */
  237.     {
  238.         active=TRUE;
  239.     }
  240.     visible=(**the_control).contrlVis;                /* Store visibility state                                        */
  241.     if(visible)                                        /* if Invisible DO NOT Draw                                        */
  242.     {
  243.         PenNormal();                                /* Set the Pen to: 1x1, PatCopy & black                            */
  244.         the_menu=get_pop_menu(the_control);            /* Get the MenuHandle                                            */
  245.         if(the_menu==NULL)                            /* Did we get a valid Menu Handle                                */
  246.         {
  247.             current_selection_text[0]='\0';            /* No - Then no selection Text                                    */
  248.             item_style=0;                            /* No Style                                                        */
  249.         }
  250.         else
  251.         {
  252.             GetItemStyle(the_menu,(**the_control).contrlValue,&item_style);            /* Yes-Get the style of the menu Item        */
  253.             GetItem(the_menu,(**the_control).contrlValue,¤t_selection_text);    /* Get the Text of the current selection    */
  254.         }
  255.         calculate_rectangles(the_control,titled,new_style,use_window_font,&title_rect,&control_rectangle);
  256.         if(titled)                                    /* Is it a Titled Pop Up Window??                                */
  257.         {
  258.             GetFontInfo(&font_info);                /* Get Font Info                                                */
  259.             text_point.v=(title_rect.top+title_rect.bottom+font_info.ascent-font_info.descent)/2;
  260.             text_point.h=title_rect.left+1;
  261.             MoveTo(text_point.h,text_point.v);        /* Move to where title is drawn                                    */
  262.             DrawString((**the_control).contrlTitle);/* Draw the Title                                                */
  263.         }
  264.         TextFont(systemFont);                        /* Use System Font for Menus                                    */
  265.         TextSize(0);                                /* Use System Size                                                */
  266.         TextFace(0);                                /* Use No Style                                                    */
  267.         convert_rectangle(&control_rectangle,TRUE);
  268.         has_enough_pixel_depth=TRUE;
  269.         if(color_qd_implemented&&(the_menu!=NULL))                                                /* Do we have color?    (Bug Fix 1.4 Final)                    */
  270.         {
  271.             if(has_enough_pixel_depth)                                                            /* Did we have enough pixel depth for color?                */
  272.             {
  273.                 GetBackColor(&background_color);                                                /* Save the current background color                        */
  274.                 GetForeColor(&foreground_color);                                                /* Save the current foreground color                        */
  275.                 item_color_ptr=NULL;                                                            /* Start the pointer at NULL                                */
  276.                 item_color_ptr=GetMCEntry((**the_menu).menuID,(**the_control).contrlValue);        /* Get the item's color table                                */
  277.                 if(item_color_ptr!=NULL)
  278.                 {
  279.                     have_item_color=TRUE;                                                        /* Store a flag that we have color for this item            */
  280.                     BlockMove(&item_color_ptr->mctRGB2,&item_foreground_color,sizeof(RGBColor));/* Copy the table, since it is relocatable                    */
  281.                     BlockMove(&item_color_ptr->mctRGB4,&item_background_color,sizeof(RGBColor));/* Copy the table, since it is relocatable                    */
  282.                     RGBBackColor(&item_background_color);                                        /* Use item's background color as backgound color for popup    */
  283.                 }
  284.                 else                                                                            /* This item does not have an individual color entry        */
  285.                 {
  286.                     item_color_ptr=GetMCEntry(0,0);                                                /* So get the system menu color table                        */
  287.                     if(item_color_ptr!=NULL)                                                    /* Did we get it?                                            */
  288.                     {
  289.                         BlockMove(&item_color_ptr->mctRGB3,&item_foreground_color,sizeof(RGBColor));/* Copy the table, since it is relocatable                */
  290.                         BlockMove(&item_color_ptr->mctRGB2,&item_background_color,sizeof(RGBColor));/* Copy the table, since it is relocatable                */
  291.                         RGBBackColor(&item_background_color);                                    /* Use item's background color as backgound color for popup    */
  292.                         have_item_color=TRUE;                                                    /* Store a flag that we have color for this item            */
  293.                     }
  294.                     else                                                                        /* Nope.  We could not get the system menu color table        */
  295.                     {
  296.                         have_item_color=FALSE;                                                    /* Store a flag that we do not have color for this item        */
  297.                     }
  298.                 }
  299.             }
  300.         }
  301.         convert_rectangle(&control_rectangle,FALSE);
  302.         InsetRect(&control_rectangle,-1,-1);                                                    /* Make the Rectangle a hare larger                            */
  303.         EraseRect(&control_rectangle);                                                            /* Erase the Rectangle                                        */
  304.         FrameRect(&control_rectangle);                                                            /* Frame it                                                    */
  305.         space_for_string=control_rectangle.right-control_rectangle.left-space_on_left;
  306.         if(active)                                                                                /* Inactive controls have no drop shadow                    */
  307.         {
  308.             MoveTo(control_rectangle.right,control_rectangle.top+2);                            /* Draw its Shadow                                            */
  309.             LineTo(control_rectangle.right,control_rectangle.bottom);
  310.             LineTo(control_rectangle.left+2,control_rectangle.bottom);
  311.         }
  312.         if(new_style)                                                                            /* If new style, draw the extra down arrow on the right        */
  313.         {
  314.             draw_pop_up_symbol(control_rectangle.right-10,(control_rectangle.bottom+control_rectangle.top)/2-3);
  315.             space_for_string-=10;
  316.         }
  317.         GetFontInfo(&font_info);                                                                /* Get Font Info (for system font)                            */
  318.         if(color_qd_implemented&&have_item_color)
  319.         {
  320.             RGBForeColor(&item_foreground_color);                                                /* Use the foreground color as the color for the menu item    */
  321.         }
  322.         if(the_menu!=NULL)
  323.         {
  324.             GetItemCmd(the_menu,(**the_control).contrlValue,&command_char);                        /* NOTE: command_char is actually an int (short for MPW C), not a char Inside Mac V-240 is incorrect!    */
  325.             switch(command_char)
  326.             {
  327.                 case    SICN_MENU:
  328.                     GetItemIcon(the_menu,(**the_control).contrlValue,&which_sicn);
  329.                     if(color_qd_implemented&&((icon_handle=(Handle)GetCIcon(which_sicn+256))!=NULL))    /* NOTE:  This is here only because under Color QD, the menu Manager looks         */
  330.                     {                                                                                    /* for a cicn before looking for a sicn, even though you specified a sicn! Bug?    */
  331.                         icon_rect.left=control_rectangle.left+space_on_left;    /* +2 removed 1.4b3    */    /* Calculate the rectangle to plot the CICN in (as a reduced CICN!)                */
  332.                         icon_rect.right=icon_rect.left+16;
  333.                         icon_rect.top=(control_rectangle.bottom+control_rectangle.top-16)/2; /* -1 rmvd 1.4b3 *//* Calculate middle of control (the -1 is new in 1.3.1)                            */
  334.                         icon_rect.bottom=icon_rect.top+16;
  335.                         PlotCIcon(&icon_rect,icon_handle);
  336.                         DisposCIcon(icon_handle);
  337.                     }
  338.                     else
  339.                     {
  340.                         plot_sicn(the_control,control_rectangle.left+space_on_left,control_rectangle.top+3,which_sicn);        /* +2 removed 1.4b3    */
  341.                     }
  342.                     MoveTo(control_rectangle.left+space_on_left+SICN_SPACE,(control_rectangle.top+control_rectangle.bottom+font_info.ascent-font_info.descent)/2);/* Move to where Text should be drawn    */
  343.                     space_for_string-=SICN_SPACE;
  344.                     break;
  345.                 case    RICN_MENU:
  346.                     GetItemIcon(the_menu,(**the_control).contrlValue,&which_icon);
  347.                     icon_rect.left=control_rectangle.left+space_on_left;                        /* +2 removed 1.4b3    */
  348.                     icon_rect.right=icon_rect.left+16;
  349.                     icon_rect.top=(control_rectangle.bottom+control_rectangle.top-16)/2;
  350.                     icon_rect.bottom=icon_rect.top+16;
  351.                     if(color_qd_implemented&&((icon_handle=(Handle)GetCIcon(which_icon+256))!=NULL))
  352.                     {
  353.                         PlotCIcon(&icon_rect,icon_handle);
  354.                         DisposCIcon(icon_handle);
  355.                     }
  356.                     else                                                                        /* If no cicn, try for a normal Icon resource                */
  357.                     {
  358.                         icon_handle=GetResource('ICON',which_icon+256);
  359.                         if(icon_handle!=NULL)
  360.                         {
  361.                             PlotIcon(&icon_rect,icon_handle);
  362.                         }
  363.                     }
  364.                     MoveTo(control_rectangle.left+space_on_left+RICN_SPACE,(control_rectangle.top+control_rectangle.bottom+font_info.ascent-font_info.descent)/2);/* Move to where Text should be drawn    */
  365.                     space_for_string-=RICN_SPACE;
  366.                     break;
  367.                 default:
  368.                     GetItemIcon(the_menu,(**the_control).contrlValue,&which_icon);
  369.                     if(which_icon==0)
  370.                     {
  371.                         /* We have no Icon, Sicn, or reduced Icon in the Menu    */
  372.                         MoveTo(control_rectangle.left+space_on_left,(control_rectangle.top+control_rectangle.bottom+font_info.ascent-font_info.descent)/2);/* Move to where Text should be drawn    */
  373.                     }
  374.                     else
  375.                     {
  376.                         /* We have an Icon in the Menu                            */
  377.                         icon_rect.left=control_rectangle.left+space_on_left;        /* +2 removed 1.4b3    */
  378.                         icon_rect.right=icon_rect.left+32;
  379.                         icon_rect.top=(control_rectangle.bottom+control_rectangle.top-32)/2;
  380.                         icon_rect.bottom=icon_rect.top+32;
  381.                         if(color_qd_implemented&&((icon_handle=(Handle)GetCIcon(which_icon+256))!=NULL))        /* Do we have Color QD and a CICN to plot?        */
  382.                         {
  383.                             PlotCIcon(&icon_rect,icon_handle);                                                    /* Yup...Do it                                    */
  384.                             DisposCIcon(icon_handle);
  385.                         }
  386.                         else
  387.                         {
  388.                             icon_handle=GetResource('ICON',which_icon+256);                                        /* Nope...Get a normal Icon                        */
  389.                             if(icon_handle!=NULL)
  390.                             {
  391.                                 PlotIcon(&icon_rect,icon_handle);
  392.                             }
  393.                         }
  394.                         MoveTo(control_rectangle.left+space_on_left+ICON_SPACE,(control_rectangle.top+control_rectangle.bottom+font_info.ascent-font_info.descent)/2);/* Move to where Text should be drawn    */
  395.                         space_for_string-=ICON_SPACE;
  396.                     }
  397.                     break;
  398.             }
  399.         }
  400.         else
  401.         {
  402.             MoveTo(control_rectangle.left+space_on_left,(control_rectangle.top+control_rectangle.bottom+font_info.ascent-font_info.descent)/2-1);/* Move to where Text should be drawn    */
  403.         }
  404.         TextFace(item_style);
  405.         shrink_string((char *) ¤t_selection_text[0],space_for_string);        /* Shrink the text for the item if it doesn't fit (c/o JS!)    */
  406.         DrawString(current_selection_text);                                /* Draw the Text                                            */
  407.         if(!active)                                                        /* If Inactive - Dim it                                        */
  408.         {
  409.             gray_out_rectangle(&control_rectangle);                        /* Dim it by graying it                                        */
  410.         }
  411.         if(color_qd_implemented&&have_item_color)                        /* Color QD?                                                */
  412.         {
  413.             RGBForeColor(&foreground_color);                            /* Restore the original foreground color                    */
  414.             RGBBackColor(&background_color);                            /* Restore the original background color                    */
  415.         }
  416.     }
  417.     return(0l);
  418. }
  419.  
  420.  
  421. long test_control(short control_type,ControlHandle the_control,long parameter)
  422. {
  423.     Point            hit_point;
  424.     Rect            title_rect;
  425.     Rect            control_rectangle;
  426.     short            titled;
  427.     short            new_style;
  428.     short            ball_check_char;
  429.     short            use_window_font;
  430.  
  431.     hit_point.v=HiWord(parameter);                                        /* Get the Hit point from the parameter    */
  432.     hit_point.h=LoWord(parameter);
  433.     titled=control_type&TITLED_MASK;                                    /* Is there a title?                    */
  434.     new_style=control_type&NEW_STYLE_MASK;                                /* Is it a new style pop up?            */
  435.     ball_check_char=control_type&CHECK_MASK;                            /* Use the '•' check char?                */
  436.     use_window_font=control_type&useWFont;                                /* Use the Window's Font?                */
  437.     if((**the_control).contrlHilite==INACTIVE)                            /* Is the control inactive?                */
  438.     {
  439.         return(0l);                                                        /* Yes -return 0                        */
  440.     }
  441.     else
  442.     {
  443.         calculate_rectangles(the_control,titled,new_style,use_window_font,&title_rect,&control_rectangle);
  444.         if(PtInRect(hit_point,&control_rectangle))                        /* Is the point in our control?            */
  445.         {
  446.             return(IN_MENU);                                            /* Yes - Point is in our control        */
  447.         }
  448.     }
  449.     return(0l);                                                            /* Point is not in our control!            */
  450. }
  451.  
  452.  
  453. long calculate_control_region(short control_type,ControlHandle the_control,long parameter)
  454. {
  455.     short                part;
  456.     Rect                indicator_rect;
  457.  
  458.     RectRgn((RgnHandle)parameter,&(**the_control).contrlRect);            /* Set the Region                        */
  459.     return(0l);
  460. }
  461.  
  462.  
  463. long initialize_control(short control_type,ControlHandle the_control,long parameter)
  464. {
  465.     pop_up_data_handle            data_handle;
  466.  
  467.     (**the_control).contrlData=NewHandle(sizeof(pop_up_data_struct));    /* Allocate space for out struct                        */
  468.     if((**the_control).contrlData!=NULL)                                /* Were we were able to allocate it?                    */
  469.     {
  470.         HLock((**the_control).contrlData);                                /* Lock the handle                                        */
  471.         data_handle=(pop_up_data_handle)(**the_control).contrlData;        /* For easier referencing                                */
  472.         if((**the_control).contrlRfCon!=0)                                /* Resource Based Menu??                                */
  473.         {
  474.             (**data_handle).type=TRUE;                                    /* Yes - store a flag                                     */
  475.             SetResLoad(FALSE);
  476.             (**data_handle).the_menu=(MenuHandle)GetResource('MENU',(**the_control).contrlRfCon);    /* Is menu already loaded?    */
  477.             SetResLoad(TRUE);
  478.             if(*(**data_handle).the_menu==NULL)                            /* Is it a handle to a NULL resource?                    */
  479.             {
  480.                 ReleaseResource((**data_handle).the_menu);                /* Yup...Release the Resource                            */
  481.                 (**data_handle).we_loaded_the_menu=TRUE;                /* We loaded this bad boy with GetMenu!                    */
  482.                 (**data_handle).the_menu=GetMenu(LoWord((**the_control).contrlRfCon));    /* Get the Menu                            */
  483.             }
  484.             else
  485.             {
  486.                 (**data_handle).we_loaded_the_menu=FALSE;                /* Did not load this-calling application is responsible    */
  487.             }
  488.         }
  489.         else                                                            /* Dynaminc Menu                                        */
  490.         {
  491.             (**data_handle).type=FALSE;                                    /* No - store a flag                                    */
  492.             (**data_handle).we_loaded_the_menu=FALSE;                    /* We did not load the menu                                */
  493.             (**data_handle).the_menu=NULL;                                /* MenuHandle will be put in contrlRfCon by application    */
  494.         }
  495.         HUnlock((**the_control).contrlData);                            /* Unlock the Handle                                    */
  496.     }
  497.     adjust_max_and_min(the_control);                                    /* After Initializing, adjust the Max and Min            */
  498.     (**the_control).contrlAction = (ProcPtr) -1;                        /* 1.3.2-Require use of AutoTrack                        */
  499.     return(0l);
  500. }
  501.  
  502.  
  503. long dispose_control(short control_type,ControlHandle the_control,long parameter)
  504. {
  505.     if((**the_control).contrlData!=NULL)                                                        /* We allocated a Handle                                            */
  506.     {
  507.         if((**(pop_up_data_handle)(**the_control).contrlData).type)
  508.         {
  509.                                                                                                 /* MenuHandle is in the_menu                                        */
  510.             if((**(pop_up_data_handle)(**the_control).contrlData).we_loaded_the_menu)            /* If we loaded the menu (GetMenu)                                    */
  511.             {
  512.                 ReleaseResource((**(pop_up_data_handle)(**the_control).contrlData).the_menu);    /* we are responsible for releasing it                                */
  513.             }
  514.         }
  515.         else                                                                                    /* MenuHandle is in contrlRfCon - Application must dispose of it    */
  516.         {
  517.         }
  518.         DisposHandle((**the_control).contrlData);                                                /* Get rid of handle we allocated                                    */
  519.         (**the_control).contrlData=NULL;                                                        /* Set the data pointer to NULL (not needed, but good cleanup)        */
  520.     }
  521.     return(0l);
  522. }
  523.  
  524.  
  525. long position_control(short control_type,ControlHandle the_control,long parameter)
  526. {
  527.     return(0l);
  528. }
  529.  
  530.  
  531. long thumb_control(short control_type,ControlHandle the_control,long parameter)
  532. {
  533.     return(0l);
  534. }
  535.  
  536.  
  537. long drag_control(short control_type,ControlHandle the_control,long parameter)
  538. {
  539.     return(1l);
  540. }
  541.  
  542.  
  543. long auto_track_control(short control_type,ControlHandle the_control,long parameter)
  544. {
  545.     Point            pop_up_point;
  546.     short            current_selection;
  547.     short            new_choice;
  548.     long            chosen;
  549.     MenuHandle        the_menu;
  550.     Rect            title_rect;
  551.     Rect            control_rectangle;
  552.     short            titled;
  553.     short            new_style;
  554.     short            ball_check_char;
  555.     short            use_window_font;
  556.     Handle            mctb_handle;
  557.     short            nEntries;
  558.     short            color_qd_implemented;
  559.  
  560.     the_menu=get_pop_menu(the_control);                                /* Get the Menu Handle                                                */
  561.     color_qd_implemented=check_color();
  562.     if(the_menu==NULL)                                                /* If no menu has been declared, we can't pop it up                    */
  563.     {
  564.         return(1l);                                                    /* Let Control Manager know that we dragged the control                */
  565.     }
  566.     InsertMenu(the_menu,-1);                                         /* Insert the Menu Into the Menu List                                */
  567.     titled=control_type&TITLED_MASK;                                /* Titled Menu???                                                    */
  568.     new_style=control_type&NEW_STYLE_MASK;                            /* New Style Pop Up?                                                */
  569.     ball_check_char=control_type&CHECK_MASK;                        /* Use the '•' check char?                                            */
  570.     use_window_font=control_type&useWFont;                            /* Use the Window's Font?                                            */
  571.     calculate_rectangles(the_control,titled,new_style,use_window_font,&title_rect,&control_rectangle);
  572.     pop_up_point.v=control_rectangle.top;                            /* Calculate the Pop Up point                                        */
  573.     pop_up_point.h=control_rectangle.left;
  574.     if(titled)                                                        /* Titled Menu???                                                    */
  575.     {
  576.         InvertRect(&title_rect);                                    /* Invert the Title as per Mac User Interface Guidelines            */
  577.     }
  578.     LocalToGlobal(&pop_up_point);                                     /* Convert the Point to Global for Menu Manager                        */
  579.     current_selection=(**the_control).contrlValue;                    /* Get the Selected Item from contrlValue                            */
  580.     if(ball_check_char)                                                /* Use the '•' as the check character?    (My personal Favorite-CF)    */
  581.     {
  582.         SetItemMark(the_menu,current_selection,'•');                /* Yes - Do it!                                                        */
  583.     }
  584.     else
  585.     {
  586.         SetItemMark(the_menu,current_selection,(char) 18);            /* No - Use the Check Mark                                            */
  587.     }
  588.     CalcMenuSize(the_menu);                                            /* We must perform this initially                                    */
  589.     trap_calc_menu_size(TRUE);                                        /* Redefine the CalcMenuSize trap to our dummy routine    (1.4b2)        */
  590.     if((control_rectangle.right-control_rectangle.left)>(**the_menu).menuWidth)    /* Is the width we are using greater than the actual menuWidth? (because of triangle) (1.4b2)    */
  591.     {
  592.         (**the_menu).menuWidth=control_rectangle.right-control_rectangle.left;    /* Yup.  Adjust the width that we will pop up    (1.4b2)    */
  593.     }
  594.     RememberA4();                                                    /* Remember this so our trap of CalcMenuSize can use globals        */
  595.     pop_up_menu_width=(**the_menu).menuWidth;                        /* Store this for use by our CalcMenuSize trap code                    */
  596.     chosen=PopUpMenuSelect(the_menu,pop_up_point.v,pop_up_point.h,current_selection);    /* Pop It Up (Dude!)                            */
  597.     trap_calc_menu_size(FALSE);                                        /* Restore the correct CalcMenuSize trap                            */
  598.     if(titled)                                                        /* Titled Menu???                                                    */
  599.     {
  600.         InvertRect(&title_rect);                                    /* Invert the Title as per Mac User Interface Guidelines            */
  601.     }
  602.     SetItemMark(the_menu,current_selection,' ');                    /* Remove the Mark                                                    */
  603.     DeleteMenu((**the_menu).menuID);                                /* Remove the Menu from the Menu List (Corrected in 1.3.2 THNX JS!)    */
  604.     /* This code thanks to Doug McKenna:                        */
  605.     /*    (Also thanks to Jeremy Grodberg)                        */
  606.     if (color_qd_implemented)
  607.     {
  608.         mctb_handle=Get1Resource('mctb',(**the_menu).menuID);                                /* Get a handle to the resource                */
  609.         if(mctb_handle!=NULL)                                                                /* Is the Handle OK?                        */
  610.         {
  611.             nEntries=(GetHandleSize(mctb_handle)-sizeof(short))/sizeof(MCEntry);            /* Calculate the number of entries            */
  612.             HLock(mctb_handle);                                                                /* Lock the Handle                            */
  613.             SetMCEntries(nEntries, (MCTablePtr)((*(char **)mctb_handle)+sizeof(short)));    /* Set the entries in the table                */
  614.             HUnlock(mctb_handle);                                                            /* Unlock the Handle                        */
  615.             ReleaseResource(mctb_handle);                                                    /* Release the Resource                        */
  616.         }
  617.     }
  618.     if(HiWord(chosen)!=0)                                                    /* Did the user choose anything in the menu??                        */
  619.     {
  620.         new_choice=LoWord(chosen);                                     /* Yes, get which item                                                */
  621.         if(new_choice!=current_selection)                            /* Different than the current one??                                    */
  622.         {
  623.             (**the_control).contrlValue=new_choice;                    /* Yes, Store the new choice                                        */
  624.             InsetRect(&control_rectangle,-1,-1);                    /* Now form a rectangle to be erased, because the height can change    */
  625.             control_rectangle.bottom+=1;
  626.             control_rectangle.right+=1;
  627.             EraseRect(&control_rectangle);                            /* Erase it.                                                        */
  628.             return(1l);
  629.         }
  630.         return(0l);                                                    /* We popped it, but did not change the value!                        */
  631.     }
  632.     return(0l);                                                        /* User did not make a choice                                        */
  633. }
  634.  
  635.  
  636. draw_pop_up_symbol(short h,short v)                                        /* Draw the downward pointing triangle for new styled pop ups        */
  637. {
  638.     short    loop;
  639.  
  640.     for(loop=0;loop<6;++loop)                                        /* Loop through the six lines of the triangle    */
  641.     {
  642.         MoveTo(h+loop-6,v+loop);                                    /* Move to beginning of each line                */
  643.         Line(10-(loop*2),0);                                        /* Draw line of appropriate length                */
  644.     }
  645. }
  646.  
  647.  
  648. save_pen_font(ControlHandle the_control,pen_font_struct *save_struct)
  649. {
  650.     GetPenState(&(*save_struct).save_pen);
  651.     (*save_struct).save_font=(*(**the_control).contrlOwner).txFont;                /* Save off the font                    */
  652.     (*save_struct).save_size=(*(**the_control).contrlOwner).txSize;                /* Save off the size                    */
  653.     (*save_struct).save_face=(*(**the_control).contrlOwner).txFace;                /* Save off the style                    */
  654. }
  655.  
  656.  
  657. set_pen_font(pen_font_struct *save_struct)
  658. {
  659.     SetPenState(&(*save_struct).save_pen);
  660.     TextFont((*save_struct).save_font);                                            /* Restore the font                        */
  661.     TextSize((*save_struct).save_size);                                            /* Restore the size                        */
  662.     TextFace((*save_struct).save_face);                                            /* Restore the style                    */
  663. }
  664.  
  665.  
  666. calculate_rectangles(ControlHandle the_control,short titled,short new_style,short use_window_font,Rect *title_rect,Rect *control_rectangle)
  667. {
  668.     MenuHandle            the_menu;
  669.     pop_up_data_handle    data_handle;
  670.     short                command_char;
  671.     short                which_icon;
  672.     short                menu_height;
  673.  
  674.     HLock((**the_control).contrlData);                                    /* Lock the control data area                                */
  675.     data_handle=(pop_up_data_handle)(**the_control).contrlData;            /* Set our own formatted handle to it                        */
  676.     the_menu=get_pop_menu(the_control);                                    /* Get a handle to the menu we are dealing with                */
  677.     if(the_menu==NULL)                                                    /* Did we not get a menu?                                    */
  678.     {
  679.         menu_height=NORMAL_MENU_SIZE;                                    /* Did not get menu. Set height to normal menu item height    */
  680.     }
  681.     else                                                                /* We did get a menu.                                        */
  682.     {
  683.         CalcMenuSize(the_menu);                                            /* Calculate the menu size                                    */
  684.         GetItemCmd(the_menu,(**the_control).contrlValue,&command_char);    /* Get the command char to determine if we have a sicn,    etc.*/
  685.         switch(command_char)
  686.         {
  687.             case    SICN_MENU:
  688.                             menu_height=SICN_MENU_SIZE;
  689.                             break;
  690.             case    RICN_MENU:
  691.                             menu_height=SICN_MENU_SIZE;
  692.                             break;
  693.             default:
  694.                     GetItemIcon(the_menu,(**the_control).contrlValue,&which_icon);
  695.                     if(which_icon==0)
  696.                     {
  697.                         menu_height=NORMAL_MENU_SIZE;
  698.                     }
  699.                     else
  700.                     {
  701.                         menu_height=ICON_MENU_SIZE;
  702.                     }
  703.                     break;
  704.         }
  705.     }
  706.     if(titled)        /* Calculate Rectangles for Titled Menus:        */
  707.     {
  708.         if(use_window_font)                                            /* Are we to use the window font??        */
  709.         {
  710.             TextFont((*(**the_control).contrlOwner).txFont);        /* Yep.  Get the font                    */
  711.             TextSize((*(**the_control).contrlOwner).txSize);        /* Get the font size                    */
  712.             TextFace((*(**the_control).contrlOwner).txFace);        /* Get the window's Face                */
  713.         }
  714.         else                                                        /* Nope.                                */
  715.         {
  716.             TextFont(0);                                            /* Use the System Font                    */
  717.             TextSize(0);                                            /* Use the System Point Size            */
  718.             TextFace(0);                                            /* No Text Face                            */
  719.         }
  720.  
  721.         (*title_rect).top=((**the_control).contrlRect.top+(**the_control).contrlRect.bottom)/2-8;
  722.         (*title_rect).left=(**the_control).contrlRect.left;
  723.         (*title_rect).bottom=(*title_rect).top+16;
  724.         (*title_rect).right=(*title_rect).left+StringWidth((**the_control).contrlTitle)+3;    /* Changed from +1 to keep title moved slightly from the menu item    */
  725.  
  726.         (*control_rectangle).left=(*title_rect).right+1;                    /* Changed from +3 to remove space between title rect and menu item (JS)    */
  727.         (*control_rectangle).top=((**the_control).contrlRect.top+(**the_control).contrlRect.bottom-menu_height)/2;
  728.         (*control_rectangle).bottom=(*control_rectangle).top+menu_height;
  729.         if(the_menu!=NULL)
  730.         {
  731.             (*control_rectangle).right=(*control_rectangle).left+(**the_menu).menuWidth;
  732.             if(new_style)                                            /* New style of pop up?                                                        */
  733.             {
  734.                 (*control_rectangle).right+=EXTRA_SPACE_FOR_NEW_STYLE;    /* Yup. Now that we can pop up a menu of any size, go ahead and add space    */
  735.             }
  736.         }
  737.         else
  738.         {
  739.             /* No Menu has been declared!                            */
  740.             (*control_rectangle).right=(**the_control).contrlRect.right;    /* Empty menu is displayed as large as the control rectangle (JS)            */
  741.         }
  742.     }
  743.     else                                                            /* Calculate Rectangles for Untitled Menus:                                    */
  744.     {
  745.         (*control_rectangle).top=((**the_control).contrlRect.top+(**the_control).contrlRect.bottom-menu_height)/2;
  746.         (*control_rectangle).bottom=(*control_rectangle).top+menu_height;
  747.         (*control_rectangle).left=(**the_control).contrlRect.left;
  748.         if(the_menu!=NULL)
  749.         {
  750.             (*control_rectangle).right=(*control_rectangle).left+(**the_menu).menuWidth;
  751.             if(new_style)                                            /* New style of pop up?                                                        */
  752.             {
  753.                 (*control_rectangle).right+=EXTRA_SPACE_FOR_NEW_STYLE;    /* Yup. Now that we can pop up a menu of any size, go ahead and add space    */
  754.             }
  755.         }
  756.         else
  757.         {
  758.             /* No Menu has been declared!                            */
  759.             (*control_rectangle).right=(**the_control).contrlRect.right;    /* Empty menu is displayed as large as the control rectangle (JS)            */
  760.         }
  761.     }
  762.     if((*control_rectangle).right>(**the_control).contrlRect.right)        /* (1.4-c/o JS)  The control rectangle will not be made    larger than            */
  763.     {                                                                /* the contrlRect specified.  Instead the item text will be shrunk.            */
  764.         (*control_rectangle).right=(**the_control).contrlRect.right;
  765.     }
  766.     HUnlock((**the_control).contrlData);                            /* Unlock the contrlData Handle                                                */
  767. }
  768.  
  769.  
  770. gray_out_rectangle(Rect *the_rectangle)
  771. {
  772.     Pattern        dim_pattern;
  773.  
  774.     StuffHex(&dim_pattern,"\pAA55AA55AA55AA55");            /* Grey Pattern                            */
  775.     PenPat(dim_pattern);                                    /* Set the Pen to the Pattern            */
  776.     PenMode(patBic);                                        /* Set the Pen Mode                        */
  777.     InsetRect(the_rectangle,1,1);                            /* Do not want to dim the Frame            */
  778.     PaintRect(the_rectangle);                                /* Dim it                                */
  779. }
  780.  
  781.  
  782. MenuHandle get_pop_menu(ControlHandle the_control)                                            /* Return the menu of the control                    */
  783. {
  784.     if((**(pop_up_data_handle)(**the_control).contrlData).type==TRUE)                        /* Is it in the data structure?                        */
  785.     {
  786.         /* Menu is in pop_up_data_handle    */                                                /*     Yes                                                */
  787.         return((MenuHandle)(**(pop_up_data_handle)(**the_control).contrlData).the_menu);    /* Return the menu                                    */
  788.     }
  789.     else                                                                                    /* No, User should have placed it in contrlRfCon    */
  790.     {
  791.         /* Menu Handle is in contrlRfCon    */
  792.         return((MenuHandle)(**the_control).contrlRfCon);                                    /* Return the menu                                    */
  793.     }
  794. }
  795.  
  796.  
  797. plot_sicn(ControlHandle the_control,short h,short v,short which_sicn)
  798. {
  799.     BitMap        src_bits;
  800.     SICNHand    the_sicn;
  801.     Rect        the_rect;
  802.  
  803.     the_sicn=(SICNHand)GetResource('SICN',which_sicn+256);                    /* Get the SICN Resource (+256 because you must subtract 256 when you put    */
  804.     if(the_sicn!=NULL)                                                        /* it in the menu structure.  Macintosh Technical Note #253                    */
  805.     {
  806.         HLock(the_sicn);                                                    /* Lock it up!                            */        
  807.         if(GetHandleSize(the_sicn)<sizeof(SICN))                            /* Check the size of the resource        */
  808.         {
  809.             /* This should NEVER happen.  It means that the SICN resource was    */
  810.             /* less than the required size, so do not attempt to plot it!        */
  811.         }
  812.         else
  813.         {
  814.             /* This code is care of Macintosh Technical Note #252        */
  815.             src_bits.baseAddr=(Ptr)(*the_sicn)[0];
  816.             src_bits.rowBytes=2;
  817.             SetRect(&src_bits.bounds,0,0,16,16);
  818.             SetRect(&the_rect,h,v,h+16,v+16);
  819.             CopyBits(&src_bits,&(*(**the_control).contrlOwner).portBits,&src_bits.bounds,&the_rect,srcCopy,NULL);
  820.         }
  821.         HUnlock(the_sicn);
  822.     }
  823. }
  824.  
  825.  
  826. adjust_max_and_min(ControlHandle the_control)
  827. {
  828.     MenuHandle    the_menu;
  829.     
  830.     the_menu=get_pop_menu(the_control);                        /* Get the menu Handle                        */
  831.     if(the_menu!=NULL)                                        /* Did we get one?                            */
  832.     {
  833.         (**the_control).contrlMin=1;                        /* Yes - Menu's lowest value is always 1    */
  834.         (**the_control).contrlMax=CountMItems(the_menu);    /* Max value is number of items                */
  835.     }
  836.     else                                                    /* No - No Menu Set Default values            */
  837.     {
  838.         (**the_control).contrlMin=1;                        /* Min Defaults to 1                        */
  839.         (**the_control).contrlMax=1;                        /* Max Defaults to 1                        */
  840.     }
  841. }
  842.  
  843.  
  844. void shrink_string(char *s, short space_for_string)
  845. {
  846.     short    s_pix;
  847.     short    s_len;
  848.  
  849.     if (space_for_string<=0)        /* Do we have any space for string?    */
  850.     {
  851.         space_for_string=0;            /* No.                                */
  852.         s[0]='\0';                    /* Make string an empty string        */
  853.     }
  854.     s_pix = StringWidth(s);
  855.     if (s_pix > space_for_string)
  856.     {
  857.         s_len = s[0];
  858.         space_for_string -= CharWidth('…');
  859.         if(space_for_string<=0)
  860.         {
  861.             space_for_string=0;
  862.             s[0]='\0';
  863.         }
  864.         else
  865.         {
  866.             for(s_len = s[0]; s_len && s_pix >= space_for_string; --s_len)
  867.             {
  868.                 s_pix -= CharWidth(s[s_len]);
  869.             }
  870.             ++s_len;
  871.             s[s_len] = '…';
  872.             s[0] = (unsigned char) s_len;
  873.         }
  874.     }
  875. }
  876.  
  877.  
  878. pascal void new_calc_menu_size(MenuHandle the_menu)
  879. {
  880.     long    save_d1;
  881.  
  882.     /*     The object of this routine is to be a dummy to replace    */
  883.     /*    CalcMenuSize when PopUpMenuSelect calls it.  This will    */
  884.     /*  call the real CalcMenuSize, but replace the menuWidth    */
  885.     /*    calculated with the one we actually want.  This will    */
  886.     /*    allow the CDEF to “pop-up” a larger menu. (i.e. with    */
  887.     /*    space for the downward pointing triangle)  This seems    */
  888.     /*    to be a better approach then crunching the text in, or    */
  889.     /*    re-writing PopUpMenuSelect (no thanks).                    */
  890.  
  891.     asm
  892.     {
  893.         move.l    d1,save_d1                            ; Save the D1 register
  894.     }
  895.     SetUpA4();                                        /* Restore the A4 world so we can use our globals        */
  896.     CallPascal(the_menu,real_calc_menu_size);        /* Call the real CalcMenuSize                            */
  897.     (**the_menu).menuWidth=pop_up_menu_width;        /* Replace the menuWidth with our value                    */
  898.     RestoreA4();                                    /* Restore the A4 world                                    */
  899.     asm
  900.     {
  901.         move.l    save_d1,d1                            ; Restore the D1 register
  902.     }
  903. }
  904.  
  905.  
  906. trap_calc_menu_size(short remove)
  907. {
  908.     if(remove)                                                    /* Are we installing our dummy routine??        */
  909.     {
  910.         real_calc_menu_size=(void *)GetTrapAddress(0x148);        /* Yup.  Get the old trap address                */
  911.         SetTrapAddress((void *)new_calc_menu_size,0x148);        /* Install the new one.                            */
  912.     }
  913.     else                                                        /* Nope.  We are restoring the old address        */
  914.     {
  915.         SetTrapAddress(real_calc_menu_size,0x148);                /* So do it.                                    */
  916.     }
  917. }
  918.  
  919.  
  920. void convert_rectangle(Rect *conversion_rectangle,short to_global)
  921. {
  922.     Point    conversion_point;
  923.     
  924.     conversion_point.v=(*conversion_rectangle).top;                /* This converts a rectangle from local to global coords    */
  925.     conversion_point.h=(*conversion_rectangle).left;
  926.     if(to_global)
  927.     {
  928.         LocalToGlobal(&conversion_point);
  929.     }
  930.     else
  931.     {
  932.         GlobalToLocal(&conversion_point);
  933.     }
  934.     (*conversion_rectangle).top=conversion_point.v;
  935.     (*conversion_rectangle).left=conversion_point.h;
  936.     conversion_point.v=(*conversion_rectangle).bottom;
  937.     conversion_point.h=(*conversion_rectangle).right;
  938.     if(to_global)
  939.     {
  940.         LocalToGlobal(&conversion_point);
  941.     }
  942.     else
  943.     {
  944.         GlobalToLocal(&conversion_point);
  945.     }
  946.     (*conversion_rectangle).bottom=conversion_point.v;
  947.     (*conversion_rectangle).right=conversion_point.h;
  948. }
  949.  
  950.  
  951. check_color()
  952. {
  953.     SysEnvRec        the_environment;                /* Environment record to determine if Color QD is implemented    */
  954.  
  955.     SysEnvirons(1,&the_environment);                /* Have machine tell us the environment                            */
  956.     if(the_environment.hasColorQD)                    /* Color QD available?                                            */
  957.     {
  958.         return(TRUE);                                /* Yup.                                                            */
  959.     }
  960.     else
  961.     {
  962.         return(FALSE);                                /* Nope.                                                        */
  963.     }
  964. }